package com.ruoyi.business.modbus.monitor;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ruoyi.business.modbus.domain.ModbusMasterDevice;
import com.ruoyi.business.modbus.domain.ModbusTcpMasterDevice;
import com.ruoyi.business.modbus.domain.ModbusReadRequest;
import com.ruoyi.business.modbus.domain.ModbusReadResponse;
import com.ruoyi.business.modbus.domain.ModbusWriteResponse;

import java.util.List;
import java.util.Map;

/**
 * Modbus网络监控AOP切面
 * 自动记录Modbus操作的响应时间和成功率
 * 
 * @author ruoyi
 * @date 2024-01-01
 */
@Aspect
@Component
public class ModbusNetworkMonitorAspect {
    
    private static final Logger log = LoggerFactory.getLogger(ModbusNetworkMonitorAspect.class);
    
    @Autowired
    private NetworkStabilityMonitor networkStabilityMonitor;
    
    /**
     * 监控所有Modbus读写操作
     * 包括：读保持寄存器、读输入寄存器、读线圈、读离散输入、写操作、测试连接、批量读取
     */
    @Around("execution(* com.ruoyi.business.modbus.service.modbus4j.AbstractModbus4jService.read*(..)) || " +
            "execution(* com.ruoyi.business.modbus.service.modbus4j.AbstractModbus4jService.write*(..)) || " +
            "execution(* com.ruoyi.business.modbus.service.modbus4j.AbstractModbus4jService.testConnection(..)) || " +
            "execution(* com.ruoyi.business.modbus.service.modbus4j.AbstractModbus4jService.batchRead(..))")
    public Object monitorModbusOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        
        // 提取设备信息（deviceSN、IP、端口）
        DeviceInfo deviceInfo = extractDeviceInfo(joinPoint.getArgs());
        String deviceSN = deviceInfo != null ? deviceInfo.deviceSN : null;
        String ipAddress = deviceInfo != null ? deviceInfo.ipAddress : null;
        Integer port = deviceInfo != null ? deviceInfo.port : null;
        
        boolean success = false;
        Object result = null;
        Throwable exception = null;
        
        try {
            // 执行原方法
            result = joinPoint.proceed();
            success = isOperationSuccessful(result, methodName);
            return result;
            
        } catch (Throwable e) {
            exception = e;
            success = false;
            throw e;
            
        } finally {
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 记录网络稳定性数据（包含IP和端口）
            if (deviceSN != null) {
                networkStabilityMonitor.recordConnectionAttempt(deviceSN, success, responseTime, ipAddress, port);
                
                // 记录详细日志（仅在调试模式下）
                if (log.isTraceEnabled()) {
                    log.trace("Modbus操作监控: 设备={}, 方法={}, 成功={}, 响应时间={}ms, 异常={}", 
                        deviceSN, methodName, success, responseTime, 
                        exception != null ? exception.getClass().getSimpleName() : "无");
                }
                
                // 如果响应时间过长，记录警告
                if (responseTime > 5000) {
                    log.warn("Modbus操作响应时间过长: 设备={}, 方法={}, 响应时间={}ms", 
                        deviceSN, methodName, responseTime);
                }
                
                // 如果操作失败，记录详细信息
                if (!success) {
                    log.debug("Modbus操作失败: 设备={}, 方法={}, 响应时间={}ms, 原因={}", 
                        deviceSN, methodName, responseTime, 
                        exception != null ? exception.getMessage() : "返回值异常");
                }
                
                // 定期输出稳定性报告（每100次操作）
                NetworkStabilityMonitor.ConnectionStats stats = networkStabilityMonitor.deviceStats.get(deviceSN);
                if (stats != null && stats.getTotalAttempts() % 100 == 0) {
                    logStabilityReport(deviceSN, stats);
                }
            }
        }
    }
    
    /**
     * 专门监控批量读取操作的详细信息
     */
    @Around("execution(* com.ruoyi.business.modbus.service.modbus4j.AbstractModbus4jService.batchRead(..))")
    public Object monitorBatchReadOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        
        // 提取批量读取的详细信息
        if (args.length >= 2 && args[1] instanceof List) {
            @SuppressWarnings("unchecked")
            List<ModbusReadRequest> requests = (List<ModbusReadRequest>) args[1];
            
            DeviceInfo deviceInfo = extractDeviceInfo(args);
            String deviceSN = deviceInfo != null ? deviceInfo.deviceSN : null;
            if (deviceSN != null && !requests.isEmpty()) {
                log.debug("开始批量读取监控: 设备={}, 请求数={}", deviceSN, requests.size());
                
                // 记录批量读取的详细请求信息
                if (log.isTraceEnabled()) {
                    for (ModbusReadRequest request : requests) {
                        log.trace("批量读取请求: 设备={}, 请求ID={}, 从站={}, 功能码={}, 地址={}, 数量={}", 
                            deviceSN, request.getRequestId(), request.getSlaveAddress(), 
                            request.getFunctionCode(), request.getStartAddress(), request.getQuantity());
                    }
                }
            }
        }
        
        // 执行原有的监控逻辑
        return monitorModbusOperation(joinPoint);
    }
    /**
     * 设备信息内部类
     */
    private static class DeviceInfo {
        String deviceSN;
        String ipAddress;
        Integer port;
        
        DeviceInfo(String deviceSN, String ipAddress, Integer port) {
            this.deviceSN = deviceSN;
            this.ipAddress = ipAddress;
            this.port = port;
        }
    }
    
    /**
     * 从方法参数中提取设备信息（deviceSN、IP、端口）
     */
    private DeviceInfo extractDeviceInfo(Object[] args) {
        if (args == null || args.length == 0) {
            return null;
        }
        
        // 第一个参数通常是ModbusMasterDevice
        for (Object arg : args) {
            if (arg instanceof ModbusMasterDevice) {
                ModbusMasterDevice device = (ModbusMasterDevice) arg;
                String deviceSN = device.getDeviceSN();
                String ipAddress = null;
                Integer port = null;
                
                // 如果是TCP设备，提取IP和端口
                if (device instanceof ModbusTcpMasterDevice) {
                    ModbusTcpMasterDevice tcpDevice = (ModbusTcpMasterDevice) device;
                    ipAddress = tcpDevice.getIpAddress();
                    port = tcpDevice.getPort();
                }
                
                return new DeviceInfo(deviceSN, ipAddress, port);
            }
        }
        
        return null;
    }
    
    
    /**
     * 判断操作是否成功
     */
    private boolean isOperationSuccessful(Object result, String methodName) {
        if (result == null) {
            return false;
        }
        
        // 根据不同的方法类型判断成功与否
        switch (methodName) {
            case "testConnection":
                // testConnection返回ModbusReadResponse<Boolean>，需要检查其success字段
                if (result instanceof ModbusReadResponse) {
                    return ((ModbusReadResponse<?>) result).isSuccess();
                }
                // 兼容旧版本，如果是Boolean类型直接返回
                return result instanceof Boolean && (Boolean) result;
                
            case "writeSingleCoil":
            case "writeMultipleCoils":
            case "writeSingleRegister":
            case "writeMultipleRegisters":
                // 这些方法可能返回ModbusWriteResponse，需要检查其success字段
                if (result instanceof ModbusWriteResponse) {
                    return ((ModbusWriteResponse) result).isSuccess();
                }
                // 兼容旧版本，如果是Boolean类型直接返回
                return result instanceof Boolean && (Boolean) result;
                
            case "readHoldingRegisters":
            case "readInputRegisters":
                // 这些方法返回ModbusReadResponse<Integer>，需要检查其success字段
                if (result instanceof ModbusReadResponse) {
                    return ((ModbusReadResponse<?>) result).isSuccess();
                }
                // 兼容旧版本，如果是List类型且非空表示成功
                return result instanceof List && !((List<?>) result).isEmpty();
                
            case "readCoils":
            case "readDiscreteInputs":
                // 这些方法返回ModbusReadResponse<Boolean>，需要检查其success字段
                if (result instanceof ModbusReadResponse) {
                    return ((ModbusReadResponse<?>) result).isSuccess();
                }
                // 兼容旧版本，如果是List类型且非空表示成功
                return result instanceof List && !((List<?>) result).isEmpty();
                
            case "batchRead":
                // batchRead返回ModbusReadResponse<Object>，需要检查其success字段
                if (result instanceof ModbusReadResponse) {
                    return ((ModbusReadResponse<?>) result).isSuccess();
                }
                // 兼容旧版本，如果是Map类型且非空表示成功
                return result instanceof Map && !((Map<?, ?>) result).isEmpty();
                
            default:
                // 其他情况，非null表示成功
                return true;
        }
    }
    
    /**
     * 输出稳定性报告
     */
    private void logStabilityReport(String deviceSN, NetworkStabilityMonitor.ConnectionStats stats) {
        try {
            NetworkStabilityMonitor.NetworkStabilityResult result = networkStabilityMonitor.isNetworkStable(deviceSN);
            String qualityLevel = networkStabilityMonitor.getNetworkQualityLevel(deviceSN);
            
            double successRatePercent = Math.round(stats.getSuccessRate() * 1000) / 10.0;
            log.info("设备网络稳定性报告: 设备={}, 稳定={}, 质量={}, 成功率={}%, 平均响应={}ms, 抖动={}ms, 总操作={}", 
                deviceSN, 
                result.isStable() ? "稳定" : "不稳定",
                qualityLevel,
                successRatePercent,
                Math.round(stats.getAverageResponseTime()),
                Math.round(stats.getResponseTimeJitter()),
                stats.getTotalAttempts());
                
            // 如果网络不稳定，输出详细原因
            if (!result.isStable()) {
                log.warn("设备网络不稳定详情: 设备={}, 原因={}, 失败次数={}, 最后失败时间={}", 
                    deviceSN, result.getReason(), stats.getFailureCount(),
                    stats.getLastFailureTime() > 0 ? 
                        new java.util.Date(stats.getLastFailureTime()).toString() : "从未失败");
            }
            
        } catch (Exception e) {
            log.error("输出稳定性报告时出错: {}", e.getMessage());
        }
    }
}
